انتقل إلى المحتوى الرئيسي

صفحة المراقبة

صورة صفحة المراقبة

فايلات الفولدر​

api.ts;
MonitorDeliveryTables.tsx;
MonitorTable.tsx;
useMonitorStore.ts;
useMonitor.ts;
MonitorView.tsx;

api.ts​

export const getAllTables = async (filter: string): Promise<MonitorTable[]> => {
const params = new URLSearchParams({});
params.set("status", filter);
const response = await axiosInstance.get(
`/checkout/halls/tables?${params.toString()}`
);
return response.data;
};
  • هذا راح يرجع الطاولات حسب الفلتر
    • status = All : هاي راح ترجع كل الطاولات سواء متاحة او مشغولة
    • status = Free ترجع الطاولات المتاحة وبس
    • status = Busy ترجع الطاولات المشغولة
export const getCheckoutHalls = async (): Promise<MonitorHall[]> => {
const response = await axiosInstance.get("/checkout/halls");
return response.data;
};
  • هذا راح يرجع القاعات ويا عدد الطاولات مالتها
export const getHallTables = async (
hallId: number,
filter: string
): Promise<MonitorTable[]> => {
const params = new URLSearchParams({});
params.set("status", filter);
params.set("hallId", hallId.toString());
const response = await axiosInstance.get(
`/checkout/halls/tables?${params.toString()}`
);
return response.data;
};
  • وفي حال اكو hallId هنا راح ياخذ المعرف وراح يسويلي فلتر على القاعات والطاولات

MonitorDeliveryTables.tsx​

بهاي الصفحة من راح نضغط على زر السفري الموجود بالمراقبة راح يعرض الطاولات الي عندي الخاصة بالدلفري وهنا راح يستخدم هذا ال Component علمود يعرضها

<>
<div className="flex items-center justify-between">
<div className="text-xl font-bold">
{t("pages.monitor.deliveryOrdersSection")}
</div>
<div>
<Button
className="py-8 px-6"
onClick={() => {
createNewSafariBillMutation.mutate();
}}
>
{t("pages.monitor.createDeliveryOrder")}
</Button>
</div>
</div>
<div className="mt-4 grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-3 xl:grid-cols-4 :grid-cols-5 gap-4">
{isSuccess &&
deliveryTables.map((bill) => <DeliveryTable billData={bill} />)}
</div>
</>
  • هذي الواجهة الي راح ترجع النة , بس اهم شي بهذا ال Component هو الي راح يفر عليه والي هو

    • DeliveryTable :
<button
key={String(bill.id)}
className={`relative rounded-2xl px-2 py-3 ${getDeliveryTableColor(
bill.orderStatus!,
!!bill.deliveryDriverId
)} dark:bg-[#27252C] hover:bg-gray-500/10 dark:hover:bg-white/15 flex flex-col flex-wrap items-start gap-3`}
onClick={() => {
navigate(`/safari/${bill.id}`);
}}
>
<div className="flex flex-col items-start gap-1 flex-1">
<div className="flex flex-col items-start gap-2">
<div className="grid grid-cols-2 gap-x-4 gap-y-2">
<div className="justify-self-end">رقم الطلب:</div>
<div className="justify-self-start font-bold col-span-1">
{" "}
{bill.id}
</div>
{/* <div className="justify-self-end">الحالة:</div>
<div className="justify-self-start font-bold col-span-1"> {bill.orderStatus}</div> */}
<div className="justify-self-end">اسم الزبون:</div>
<div className="justify-self-start font-bold col-span-1">
{" "}
{bill.customerName || "زبون نقدي"}
</div>
<div className="justify-self-end">رقم الزبون:</div>
<div className="justify-self-start font-bold col-span-1">
{" "}
{bill.customerPhoneNumber}
</div>
<div className="justify-self-end">الكاشير:</div>
<div className="justify-self-start font-bold col-span-1">
{" "}
{bill.cashierName}
</div>
<div className="justify-self-end">اسم السائق:</div>
<div className="justify-self-start font-bold col-span-1">
{" "}
{bill.deliveryDriverName}
</div>
<div className="justify-self-end">يجهز بعد:</div>
<div className="justify-self-start font-bold col-span-1">
<Timer
type={TimerType.CountDown}
launchDate={addMinutesToDate(
bill.prepTime!,
new Date(bill.orderDate!)
).toISOString()}
/>
</div>
<div className="justify-self-end">الوقت:</div>
<div className="justify-self-start font-bold col-span-1">
<Timer type={TimerType.CountUp} launchDate={bill.orderDate!} />
</div>
</div>
</div>
</div>
{bill.deliveryDriverId && (
<>
<div className="absolute top-1 end-2 text-[50px] text-black/50">
<MdDeliveryDining />
</div>
</>
)}
</button>
  • هنا هذا Component الي راح يكعد يعرض طاولة وحدة وراح يستقبل بيانات الفاتورة وراح يستخدم getDeliveryTableColor علمود يرجع ستايل بناء على حالة الاوردر
  • باقي التفاصيل بال Component هي مجرد عرض للبيانات مال الاوبجكت
export function getDeliveryTableColor(
orderStatus: string,
isDelivery: boolean
) {
let color = "bg-input";

switch (orderStatus) {
case "NeedsPrintingToKitchen":
color = "bg-yellow-100 hover:bg-yellow-200";
break;
case "NeedsPrintingToCustomer":
color = "bg-purple-100 hover:bg-purple-200";
break;
case "PrintedToCustomer":
color = "bg-sky-100 hover:bg-sky-200";
break;
case "Open":
color = "bg-[#F6F6F9]";
break;
case "Closed":
color = "bg-red-100 hover:bg-red-200";
break;
default:
break;
}

if (isDelivery) {
switch (orderStatus) {
case "NeedsPrintingToKitchen":
color = "bg-yellow-100 hover:bg-yellow-200";
break;
case "NeedsPrintingToCustomer":
color = "bg-purple-100 hover:bg-purple-200";
break;
case "PrintedToCustomer":
color = "bg-orange-100 hover:bg-orange-200";
break;
case "Open":
color = "bg-[#F6F6F9]";
break;
case "Closed":
color = "bg-red-100 hover:bg-red-200";
break;
default:
break;
}
}

return cn(color);
}
  • هاي مجموعة الحالات والشروط مالتها والستايل مال كل وحدة منهن

useCheckoutStore.ts ( فقط جزئية Monitor Types )​

export type MonitorHall = {
id: number;
hallName: string;
tables: number;
};

export type MonitorTable = {
id: number;
tableNumber: number;
orderTime: string;
status: string;
prepTime: number;
capacity: number;
numberOfItemsOnTheTable: number;
hallId: number;
hallName: string;
};
  • هذني الانواع الي راح يتم استخدامهن باللوجك مال المراقبة مالتك بدال ما كلسع تكتب الانواع وتسوي set للبيانات مالتك

MonitorTable.tsx​

type TableViewProps = {
table: MonitorTableType;
customClickFunction?: () => void;
createLabel?: string;
};
  • هنا حيكون التايب مال ال View الي همينة راح يستخدم MonitorTableType
function getTableColor(orderStatus: string) {
let color = "text-[#55C023]";
switch (orderStatus) {
case "NeedsPrintingToKitchen":
color = "text-yellow-500";
break;
case "NeedsPrintingToCustomer":
color = "text-purple-500";
break;
case "PrintedToCustomer":
color = "text-sky-500";
break;
case "Busy":
color = "text-red-500";
break;
case "Free":
color = "text-[#55C023]";
break;
default:
break;
}

return cn(color);
}
  • هنانة راح يسوي switch للون حسب الحالة مال الطلب
useEffect(() => {
const handleOrderUpdate = (params: any) => {
const bill = params as Checkout;
if (bill.tableId == table.id) {
setTable({ ...table, prepTime: bill.prepTime || 0 });
}
};

const handleOrderCreated = (params: any) => {
const bill = params as Checkout;
if (bill.tableId == table.id) {
setTable({ ...table, prepTime: bill.prepTime || 0 });
}
};

const handleOrderDeleted = (params: any) => {
const bill = params as Checkout;
if (bill.tableId == table.id) {
setTable({ ...table, prepTime: 0 });
}
};

const handleOrderFinished = (params: any) => {
const bill = params as Checkout;
if (bill.tableId == table.id) {
setTable({ ...table, prepTime: 0 });
}
};

subscribe("OrderUpdate", handleOrderUpdate);
subscribe("OrderCreated", handleOrderCreated);
subscribe("OrderDelete", handleOrderDeleted);
subscribe("OrderFinished", handleOrderFinished);

return () => {
unsubscribe("OrderUpdate", handleOrderUpdate);
unsubscribe("OrderCreated", handleOrderCreated);
unsubscribe("OrderDelete", handleOrderDeleted);
unsubscribe("OrderFinished", handleOrderFinished);
};
}, [subscribe, unsubscribe, table]);
  • هنا يخص عمليات خاصة بالمراقبة مثل تحديث والحذف وغيرها وراح يخزن القيم global عن طريق ال subscribe method

  • الباقي حيكون عرض لل UI مالتك بالصفحة وياه بعض اللوجك البسيط الي يخص العرض والستايل


useMonitorStore.tsx​

export type MonitorHall = {
id: number;
hallName: string;
tables: number;
};

type MonitorStore = {
selectedHall?: MonitorHall;
selectedTable?: MonitorTable;

setSelectedHall: (hall?: MonitorHall) => void;
setSelectedTable: (table?: MonitorTable) => void;
};
  • هاي عبارة عن Types راح يتم استخدامها بال CustomHook الاساسي الي راح نشوفة بعد شوية وبيها قيم خاصة بالقاعة والطاولات
const useMonitorStore = create<MonitorStore>((set) => ({
selectedHall: undefined,
selectedTable: undefined,

setSelectedHall: (hall?: MonitorHall) => {
set((state) => ({
selectedHall: hall,
}));
},

setSelectedTable: (table?: MonitorTable) => {
set((state) => ({
selectedTable: table,
}));
},
}));
  • هاي راح تسوي Setting للقاعة والطاولة وراح تستقبل الانواع الفوك اضافة للtype الي شفناه من صفحة ال useCheckoutStore

useMonitor​

export enum MonitorGroup {
AllTables = 0,
SelectedHall = 1,
Safari = 2,
}

export default function useMonitor() {
const [searchParams] = useSearchParams();
const [group, setGroup] = useState<MonitorGroup>(MonitorGroup.AllTables)
const [hallFilter, setHallFilter] = useState("All")
const [allTablesCount, setAllTablesCount] = useState<number>(0);
const [allTablesFilter, setAllTablesFilter] = useState("All")
const { selectedHall, setSelectedHall, selectedTable, setSelectedTable } = useMonitorStore();

const { data: halls, isLoading: isHallsLoading, isError: isHallsError } = useQuery<MonitorHall[]>({
queryKey: ["checkout-halls"],
queryFn: () => getCheckoutHalls(),
});
  • اول شي عدنة ال Enum الخاص بتحديد هل المجموعة الحالية هي الطاولات كلها ام مختار قاعة او رايح على السفري
  • ثاني شي عدنة مجموعة من ال States ومن ضمنها الخاصة باستخدام ال MonitorGroup وايضا عدنة هنا Get Request الي راح يجيب القاعات كلها
const {
data: tables,
isLoading: isTablesLoading,
isError: isTablesError,
} = useQuery<MonitorTable[]>({
queryKey: ["monitor-hall-tables", selectedHall?.id, hallFilter],
queryFn: () => {
return getHallTables(selectedHall?.id!, hallFilter);
},
enabled: !!selectedHall?.id && !!hallFilter,
});

const {
data: allTables,
isLoading: isAllTablesLoading,
isError: isAllTablesError,
} = useQuery<MonitorTable[]>({
queryKey: ["monitor-all-tables", allTablesFilter],
queryFn: () => {
return getAllTables(allTablesFilter);
},
enabled: !!allTablesFilter,
});
  • دالتين
    • getHallTables : راح ترجع الطاولات حسب القاعة المختارة مالتك وحسب الفلتر الداخل بيها
    • getAllTables : راح ترجع كل الطاولات مالتي وياها الفلتر الداخل عليها
useEffect(() => {
const groupParam = Number.parseInt(searchParams.get("group") || "0");
const hallParam = Number.parseInt(searchParams.get("hall") || "-1");
switch (groupParam) {
case 0:
setGroup(MonitorGroup.AllTables);
break;
case 1:
setGroup(MonitorGroup.SelectedHall);
if (hallParam != -1) {
for (const hall of halls ?? []) {
if (hall.id == hallParam) {
setSelectedHall(hall);
}
}
}
break;
case 2:
setGroup(MonitorGroup.Safari);
break;
default:
break;
}
}, [searchParams, halls]);
  • هاي راح تسوي Set للقيمة مال المجموعة الحالية بناء على المعطيات والي هي اما كل الطاولات = 0 او القاعة المختارة = 1او سفري = 2

والي كل وحدة راح يكون الها مرادف بال Enum الي شفناه فوك قبل شوية


monitorView.tsx​

const { $can } = useUserPermissionsStore();
const canHandleDeliveryOrders = $can(AllPermissions.HandleDeliveryOrders);
  • هذا عبارة عن Permission راح نشرحة بعدين بالملفات المشتركة , بس بشكل عام هذا راح يخليني اروح لقائمة السفري والتعاملات مالتها لو لا والي راح يتم اضافة هاي ال Permission من فولدر الادارة من يم الادوار
function getFilterValue() {
if (group == MonitorGroup.AllTables) {
return allTablesFilter;
} else if (group == MonitorGroup.SelectedHall) {
return hallFilter;
}
}

function setFilterValue(e: any) {
if (group == MonitorGroup.AllTables) {
setAllTablesFilter(e);
return;
} else if (group == MonitorGroup.SelectedHall) {
setHallFilter(e);
return;
}
}
  • هذني الدالتين getFilterValue و setFilterValue وظيفتهن يشتغلن حسب قيمة المتغير group، واللي يحدد نوع الفلترة اللي تريد تشتغل عليها (يا جدول تريد تصفي).

    getHallFilter

  • هاي ترجع قيمة الفلتر الحالي حسب نوع group:

إذا group هو AllTables، ترجع allTablesFilter.

إذا group هو SelectedHall، ترجع hallFilter

setHallFilter هاي تستقبل قيمة جديدة e، وتحدث بيها الفلتر الصحيح حسب group:

إذا group هو AllTables، تنفذ setAllTablesFilter(e).

إذا group هو SelectedHall، تنفذ setHallFilter(e). الباقي هو ال UI الي راح ينعرض بالصفحة ويا لوجك خاص بالعرض